var net = require("net");
var ws = require("ws");

var log = require("../utils/log.js");
var tcppkg = require("./tcppkg");
var proto_man = require('../netbus/proto_man.js')
var service_manager = require('./service_manager.js');

var netbus = {
	start_tcp_server : start_tcp_server,
	start_ws_server : start_ws_server,
	session_send : session_send,
	session_close : session_close,
};

//全局的链接session 表
var global_session_list = {};
var global_seesion_key = 1;

/**
 * 有客户端的session接入进来
 * @param {*} session 
 * @param {*} proto_type 
 * @param {*} is_ws 是websocket 还是 tcp 
 */
function on_session_enter(session, proto_type, is_ws) {
	if (is_ws) {
		log.info("session enter ws", session._socket.remoteAddress, session._socket.remotePort);
	}
	else {
		log.info("session enter tcp", session.remoteAddress, session.remotePort);	
	}
	
	session.last_pkg = null; // 表示我们存储的上一次没有处理完的TCP包;
	session.is_ws = is_ws;
	session.proto_type = proto_type;

	// 加入到我们的serssion 列表里面
	global_session_list[global_seesion_key] = session;
	session.session_key = global_seesion_key;
	global_seesion_key ++;
	// end 
}

function on_session_exit(session) {
	log.info("session exit !!!!");
	service_manager.on_client_lost_connect(session);
	session.last_pkg = null; 
    //移除
	if (global_session_list[session.session_key]) {
		global_session_list[session.session_key] = null;
		delete global_session_list[session.session_key]; // 把这个key, value从 {}里面删除
		session.session_key = null;
	}
}

// 一定能够保证是一个整包;
// 如果是json协议 str_or_buf json字符串;
// 如果是buf协议 str_or_buf Buffer对象;
function on_session_recv_cmd(session, str_or_buf) {
	log.info(str_or_buf);
	//如果没办法处理，关掉请求
	if(!service_manager.on_recv_client_cmd(session,str_or_buf)){
		session_close(session);
	};
}

// 发送命令
function session_send(session, cmd) {
	if (!session.is_ws) { // tcp 消息
		var data = tcppkg.package_data(cmd);
		session.write(data);
		return;
	}
	else {
		session.send(cmd);
	}
}

// 关闭一个session
function session_close(session) {
	if (!session.is_ws) { //tcp socket
		session.end();
		return;
	} 
	else { //websocket
		session.close();
	}
}

// --------------------------------------------------------------
function add_client_session_event(session, proto_type) {
	session.on("close", function() {
		on_session_exit(session);
	});

     //服务收到数据拆包
	session.on("data", function(data) {
		// 
		if (!Buffer.isBuffer(data)) { // 不合法的数据
			session_close(session);
			return;
		}
		// end 

		var last_pkg = session.last_pkg;
		if (last_pkg != null) { // 上一次剩余没有处理完的半包;
			var buf = Buffer.concat([last_pkg, data], last_pkg.length + data.length);
			last_pkg = buf;
		}
		else {
			last_pkg = data;	
		}

		var offset = 0;
		var pkg_len = tcppkg.read_pkg_size(last_pkg, offset);
		if (pkg_len < 0) {
			return;
		}

		while(offset + pkg_len <= last_pkg.length) { // 判断是否有完整的包;
			// 根据长度信息来读取我们的数据,架设我们穿过来的是文本数据
			var cmd_buf; 


			// 收到了一个完整的数据包
			if (session.proto_type == proto_man.PROTO_JSON) {
				var json_str = last_pkg.toString("utf8", offset + 2, offset + pkg_len);
                console.log('=========json_str==========',json_str);
				if (!json_str) {
					session_close(session);
					return;
				}
				on_session_recv_cmd(session, json_str);	
			}
			else {
				cmd_buf = Buffer.allocUnsafe(pkg_len - 2); // 2个长度信息
				last_pkg.copy(cmd_buf, 0, offset + 2, offset + pkg_len);
				on_session_recv_cmd(session, cmd_buf);	
			}
			

			offset += pkg_len;
			if (offset >= last_pkg.length) { // 正好我们的包处理完了;
				break;
			}

			pkg_len = tcppkg.read_pkg_size(last_pkg, offset);
			if (pkg_len < 0) {
				break;
			}
		}

		// 能处理的数据包已经处理完成了,保存 0.几个包的数据
		if (offset >= last_pkg.length) {
			last_pkg = null;
		}
		else { // offset, length这段数据拷贝到新的Buffer里面
			var buf = Buffer.allocUnsafe(last_pkg.length - offset);
			last_pkg.copy(buf, 0, offset, last_pkg.length);
			last_pkg = buf;
		}

		session.last_pkg = last_pkg;
	});

	session.on("error", function(err) {
		
	});

	on_session_enter(session, proto_type, false);
}

/**
 * 启动tcp server
 * @param {*} ip 
 * @param {*} port 
 * @param {*} proto_type 协议类型
 */
function start_tcp_server(ip, port, proto_type) {
	var str = {
		1:'PROTO_JSON',
		2:'PROTO_BUF'
	}
	log.info("start tcp server ..", ip, port,str[proto_type]);
	var server = net.createServer(function(client_sock) { 
		add_client_session_event(client_sock, proto_type);
	});


	// 监听发生错误的时候调用
	server.on("error", function() {
		log.error("server listen error");
	});

	server.on("close", function() {
		log.error("server listen close");
	});

	server.listen({
		port: port,
		host: ip,
		exclusive: true,
	});
}

// -------------------------
function isString(obj){ //判断对象是否是字符串  
	return Object.prototype.toString.call(obj) === "[object String]";  
}  

function isString1(obj) {
    return typeof obj === 'string' || obj instanceof String;
  }

// ws链接进来
function ws_add_client_session_event(session, proto_type) {
	// close事件
	session.on("close", function() {
		on_session_exit(session);
	});

	// error事件
	session.on("error", function(err) {
	});
	// end 

	session.on("message", function(data) {
        console.log('====ws_add_client_session_event==message=============',data,session.proto_type);
		if (session.proto_type == proto_man.PROTO_JSON) {
            console.log('====ws_add_client_session_event==message1=============',isString(data),Buffer.isBuffer(data))
			if (!Buffer.isBuffer(data)) {
				session_close(session);
				return;
			}
			
			//版本问题，发送json收到的是二进制
			// if (!isString(data)) {
			// 	session_close(session);
			// 	return;
			// }
			on_session_recv_cmd(session, data);
		}
		else {
			if (!Buffer.isBuffer(data)) {
				session_close(session);
				return;
			}
			on_session_recv_cmd(session, data);	
		}
	});
	// end

	on_session_enter(session, proto_type, true); 
}

/**
 *  启动websocket server
 * @param {*} ip 
 * @param {*} port 
 * @param {*} proto_type 
 */
function start_ws_server(ip, port, proto_type) {
	var str = {
		1:'PROTO_JSON',
		2:'PROTO_BUF'
	}
	log.info("start ws server ..", ip, port,str[proto_type]);
	var server = new ws.Server({
		host: ip,
		port: port,
	});

    //链接进来
	function on_server_client_comming (client_sock) {
		ws_add_client_session_event(client_sock, proto_type);
	}
	server.on("connection", on_server_client_comming);

    //监听错误
	function on_server_listen_error(err) {
		log.error("ws server listen error!!");
	}
	server.on("error", on_server_listen_error);

    //链接关闭
	function on_server_listen_close(err) {
		log.error("ws server listen close!!");
	}
	server.on("close", on_server_listen_close);
}


module.exports = netbus;

